﻿namespace Beetle
{
    using System;
    using System.Collections.Generic;
    using System.Text;

    public class BufferWriter : IDisposable
    {
        private const int _field_a = 0;
        internal Queue<Class_b> _field_b;
        internal Class_b _field_c;
        private Class_ag _field_d;
        internal int _field_e;
        private bool _field_f;
        internal IByteConverter _field_g;
        [ThreadStatic]
        private static Class_aj _field_h;
        internal IList<IMessage> _field_i;
        private bool _field_j;
        private int _field_k;
        private Class_m _field_l;
        private ByteArraySegment[] _field_m;
        private IList<ByteArraySegment> _field_n;
        public Encoding Coding;
        public bool EnabledVariant;

        public BufferWriter(Encoding coding)
        {
            this._field_b = new Queue<Class_b>(100);
            this._field_f = true;
            this._field_g = TcpUtils.ByteConverters.Pop();
            this._field_i = new List<IMessage>(0x40);
            this._field_l = new Class_m();
            this._field_m = new ByteArraySegment[] { new ByteArraySegment(), new ByteArraySegment(), new ByteArraySegment() };
            this._field_n = new List<ByteArraySegment>(4);
            this.Coding = coding;
            this._field_d = Class_ag.b();
            this.a();
            this._field_f = true;
        }

        internal BufferWriter(Encoding A_0, Class_ag A_1)
        {
            this._field_b = new Queue<Class_b>(100);
            this._field_f = true;
            this._field_g = TcpUtils.ByteConverters.Pop();
            this._field_i = new List<IMessage>(0x40);
            this._field_l = new Class_m();
            this._field_m = new ByteArraySegment[] { new ByteArraySegment(), new ByteArraySegment(), new ByteArraySegment() };
            this._field_n = new List<ByteArraySegment>(4);
            this.Coding = A_0;
            this._field_d = A_1;
            this.a();
            this._field_f = true;
        }

        public BufferWriter(Encoding coding, bool bufferfromPool)
        {
            this._field_b = new Queue<Class_b>(100);
            this._field_f = true;
            this._field_g = TcpUtils.ByteConverters.Pop();
            this._field_i = new List<IMessage>(0x40);
            this._field_l = new Class_m();
            this._field_m = new ByteArraySegment[] { new ByteArraySegment(), new ByteArraySegment(), new ByteArraySegment() };
            this._field_n = new List<ByteArraySegment>(4);
            this.Coding = coding;
            if (bufferfromPool)
            {
                this._field_d = Class_ag.b();
                this.a();
            }
            this._field_f = bufferfromPool;
        }

        internal BufferWriter(Encoding A_0, Class_ag A_1, bool A_2)
        {
            this._field_b = new Queue<Class_b>(100);
            this._field_f = true;
            this._field_g = TcpUtils.ByteConverters.Pop();
            this._field_i = new List<IMessage>(0x40);
            this._field_l = new Class_m();
            this._field_m = new ByteArraySegment[] { new ByteArraySegment(), new ByteArraySegment(), new ByteArraySegment() };
            this._field_n = new List<ByteArraySegment>(4);
            this.Coding = A_0;
            this._field_d = A_1;
            this._field_f = true;
            if (A_2)
            {
                this.a();
            }
        }

        public BufferWriter(Encoding coding, bool bufferfromPool, bool allotbuffer)
        {
            this._field_b = new Queue<Class_b>(100);
            this._field_f = true;
            this._field_g = TcpUtils.ByteConverters.Pop();
            this._field_i = new List<IMessage>(0x40);
            this._field_l = new Class_m();
            this._field_m = new ByteArraySegment[] { new ByteArraySegment(), new ByteArraySegment(), new ByteArraySegment() };
            this._field_n = new List<ByteArraySegment>(4);
            this.Coding = coding;
            if (bufferfromPool)
            {
                this._field_d = Class_ag.b();
                if (allotbuffer)
                {
                    this.a();
                }
            }
            this._field_f = bufferfromPool;
        }

        private void a()
        {
            this._field_c = this._field_d.g();
            this._field_b.Enqueue(this._field_c);
        }

        private bool a(Array A_0)
        {
            if (A_0 == null)
            {
                this.Write(0);
            }
            else
            {
                this.Write(A_0.Length);
            }
            return ((A_0 != null) && (A_0.Length > 0));
        }

        private void a(uint A_0)
        {
            do
            {
                if (this._field_c.c(1))
                {
                    this._field_c.a((byte) ((A_0 & 0x7f) | 0x80));
                    this._field_e++;
                }
                else
                {
                    this.Write(new byte[] { (byte) ((A_0 & 0x7f) | 0x80) }, 0, 1);
                }
            }
            while ((A_0 = A_0 >> 7) != 0);
            this._field_c._field_e[this._field_c._field_g - 1] = (byte) (this._field_c._field_e[this._field_c._field_g - 1] & 0x7f);
        }

        private void a(ulong A_0)
        {
            do
            {
                if (this._field_c.c(1))
                {
                    this._field_c.a((byte) ((A_0 & ((ulong) 0x7fL)) | ((ulong) 0x80L)));
                    this._field_e++;
                }
                else
                {
                    this.Write(new byte[] { (byte) ((A_0 & ((ulong) 0x7fL)) | ((ulong) 0x80L)) }, 0, 1);
                }
            }
            while ((A_0 = A_0 >> 7) != 0L);
            this._field_c._field_e[this._field_c._field_g - 1] = (byte) (this._field_c._field_e[this._field_c._field_g - 1] & 0x7f);
        }

        private static Class_aj b()
        {
            if (_field_h == null)
            {
                _field_h = new Class_aj();
            }
            return _field_h;
        }

        internal Class_b c()
        {
            lock (this)
            {
                if ((this._field_b.Count > 0) && !this._field_j)
                {
                    return this._field_b.Peek();
                }
                return null;
            }
        }

        internal Class_b d()
        {
            lock (this)
            {
                if ((this._field_b.Count > 0) && !this._field_j)
                {
                    return this._field_b.Dequeue();
                }
                return null;
            }
        }

        public void Dispose()
        {
            lock (this)
            {
                if (!this._field_j)
                {
                    this._field_j = true;
                    if (this._field_g != null)
                    {
                        TcpUtils.ByteConverters.Push(this._field_g);
                    }
                    while (this._field_b.Count > 0)
                    {
                        this._field_b.Dequeue().Dispose();
                    }
                    this._field_n.Clear();
                    this._field_m[0].Clear();
                    this._field_m[1].Clear();
                    this._field_m[2].Clear();
                }
            }
        }

        internal void e()
        {
            while (this._field_b.Count > 0)
            {
                this._field_b.Dequeue().Dispose();
            }
        }

        public IList<ByteArraySegment> GetBuffers()
        {
            List<ByteArraySegment> list = new List<ByteArraySegment>(this._field_b.Count);
            while (this._field_b.Count > 0)
            {
                Class_b _b = this._field_b.Dequeue();
                byte[] dst = new byte[_b._field_h];
                Buffer.BlockCopy(_b._field_e, 0, dst, 0, _b._field_h);
                ByteArraySegment item = new ByteArraySegment();
                item.SetInfo(dst, 0, dst.Length);
                list.Add(item);
                _b.Dispose();
            }
            return list;
        }

        public void Reset()
        {
            this._field_e = 0;
            while (this._field_b.Count > 0)
            {
                this._field_b.Dequeue().Dispose();
            }
            this.a();
        }

        public void SetHeadSize(int size, IList<ByteArraySegment> refdata)
        {
            ByteArraySegment segment;
            byte[] bytes = this._field_g.GetBytes(size);
            if (refdata.Count == 1)
            {
                segment = refdata[0];
                Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, segment.Count);
            }
            else
            {
                segment = refdata[0];
                ByteArraySegment segment2 = refdata[1];
                Buffer.BlockCopy(bytes, 0, segment.Array, segment.Offset, segment.Count);
                Buffer.BlockCopy(bytes, segment.Count, segment2.Array, segment2.Offset, segment2.Count);
            }
        }

        public void Write<T>(IList<T> objs) where T: IMessage
        {
            if (objs == null)
            {
                this.Write(0);
            }
            else
            {
                this.Write(objs.Count);
                for (int i = 0; i < objs.Count; i++)
                {
                    this.Write(objs[i]);
                }
            }
        }

        public void Write(ByteArraySegment bas)
        {
            this.Write(bas.Count);
            this.Write(bas.Array, bas.Offset, bas.Count);
        }

        public void Write(char[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public void Write(byte value)
        {
            if (this._field_c.c(1))
            {
                this._field_c.a(value);
                this._field_e++;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 1);
            }
        }

        public void Write(IList<DateTime> values)
        {
            if (this.WriteIListLength<DateTime>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public void Write(DateTime datetime)
        {
            this.Write(datetime.Ticks);
        }

        public void Write(bool[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public void Write(IList<float> values)
        {
            if (this.WriteIListLength<float>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public void Write(bool value)
        {
            if (this._field_c.c(1))
            {
                this._field_c.a(new byte[] { value ? ((byte) 1) : ((byte) 0) });
                this._field_e++;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 1);
            }
        }

        public void Write(DateTime[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public void Write(IList<bool> values)
        {
            if (this.WriteIListLength<bool>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public unsafe void Write(char value)
        {
            short num = (short) value;
            if (this._field_c.c(2))
            {
                fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                {
                    *((short*) numRef) = num;
                }
                this._field_c._field_g += 2;
                this._field_c._field_h += 2;
                this._field_e += 2;
            }
            else
            {
                this.Write(this._field_g.GetBytes(num), 0, 2);
            }
        }

        public void Write(double[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public void Write(IList<char> values)
        {
            if (this.WriteIListLength<char>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public void Write(IMessage obj)
        {
            obj.Save(this);
        }

        public void Write(short[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public void Write(IList<double> values)
        {
            if (this.WriteIListLength<double>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public void Write(IList<string> values)
        {
            if (this.WriteIListLength<string>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public void Write(IList<long> values)
        {
            if (this.WriteIListLength<long>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public void Write(float[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public void Write(IList<short> values)
        {
            if (this.WriteIListLength<short>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public void Write(IList<int> values)
        {
            if (this.WriteIListLength<int>(values))
            {
                for (int i = 0; i < values.Count; i++)
                {
                    this.Write(values[i]);
                }
            }
        }

        public unsafe void Write(double value)
        {
            if (this.EnabledVariant)
            {
                this.WriteVariant(value);
            }
            else
            {
                long num = *((long*) &value);
                if (this._field_c.c(8))
                {
                    fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                    {
                        *((long*) numRef) = num;
                    }
                    this._field_c._field_g += 8;
                    this._field_c._field_h += 8;
                    this._field_e += 8;
                }
                else
                {
                    this.Write(this._field_g.GetBytes(num), 0, 8);
                }
            }
        }

        public void Write(int[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public unsafe void Write(int value)
        {
            if (this.EnabledVariant)
            {
                this.WriteVariant(value);
            }
            else if (this._field_c.c(4))
            {
                fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                {
                    *((int*) numRef) = value;
                }
                this._field_c._field_g += 4;
                this._field_c._field_h += 4;
                this._field_e += 4;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 4);
            }
        }

        public unsafe void Write(long value)
        {
            if (this.EnabledVariant)
            {
                this.WriteVariant(value);
            }
            else if (this._field_c.c(8))
            {
                fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                {
                    *((long*) numRef) = value;
                }
                this._field_c._field_g += 8;
                this._field_c._field_h += 8;
                this._field_e += 8;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 8);
            }
        }

        public unsafe void Write(uint value)
        {
            if (this.EnabledVariant)
            {
                this.WriteVariant(value);
            }
            else if (this._field_c.c(4))
            {
                fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                {
                    *((int*) numRef) = (int)value;
                }
                this._field_c._field_g += 4;
                this._field_c._field_h += 4;
                this._field_e += 4;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 4);
            }
        }

        public void Write(byte[] value)
        {
            int length = 0;
            if ((value != null) && (value.Length > 0))
            {
                length = value.Length;
            }
            this.Write(length);
            if (length > 0)
            {
                this.Write(value, 0, value.Length);
            }
        }

        public unsafe void Write(ushort value)
        {
            if (this._field_c.c(2))
            {
                fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                {
                    *((short*) numRef) = (short)value;
                }
                this._field_c._field_g += 2;
                this._field_c._field_h += 2;
                this._field_e += 2;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 2);
            }
        }

        public void Write(long[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public void Write(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                this.Write(0);
            }
            else
            {
                b().a(value, this.Coding, this._field_c, this, true);
            }
        }

        public void Write(string[] value)
        {
            if (this.a(value))
            {
                for (int i = 0; i < value.Length; i++)
                {
                    this.Write(value[i]);
                }
            }
        }

        public unsafe void Write(short value)
        {
            if (this._field_c.c(2))
            {
                fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                {
                    *((short*) numRef) = value;
                }
                this._field_c._field_g += 2;
                this._field_c._field_h += 2;
                this._field_e += 2;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 2);
            }
        }

        public unsafe void Write(float value)
        {
            if (this.EnabledVariant)
            {
                this.WriteVariant(value);
            }
            else
            {
                int num = *((int*) &value);
                if (this._field_c.c(4))
                {
                    fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                    {
                        *((int*) numRef) = num;
                    }
                    this._field_c._field_g += 4;
                    this._field_c._field_h += 4;
                    this._field_e += 4;
                }
                else
                {
                    this.Write(this._field_g.GetBytes(num), 0, 4);
                }
            }
        }

        public unsafe void Write(ulong value)
        {
            if (this.EnabledVariant)
            {
                this.WriteVariant(value);
            }
            else if (this._field_c.c(8))
            {
                fixed (byte* numRef = &(this._field_c._field_e[this._field_c._field_g]))
                {
                    *((long*) numRef) = (long)value;
                }
                this._field_c._field_g += 8;
                this._field_c._field_h += 8;
                this._field_e += 8;
            }
            else
            {
                this.Write(this._field_g.GetBytes(value), 0, 8);
            }
        }

        public void Write(byte[] value, int start, int length)
        {
            this._field_l.e(value, start, length);
            this._field_k = 0;
            if (this._field_f)
            {
                this._field_c.a(this._field_l);
                this._field_k += this._field_l._field_d;
                while (this._field_k < length)
                {
                    this.a();
                    this._field_c.a(this._field_l);
                    this._field_k += this._field_l._field_d;
                }
            }
            else
            {
                this._field_k = length;
                byte[] dst = new byte[length];
                Buffer.BlockCopy(value, start, dst, 0, length);
                Class_b item = new Class_b(dst);
                this._field_b.Enqueue(item);
            }
            this._field_e += this._field_k;
        }

        public IList<ByteArraySegment> WriteHeadSize()
        {
            byte[] bytes = this._field_g.GetBytes(0);
            return this.WriteReturnSegment(bytes, 0, 4);
        }

        private bool WriteIListLength<T>(IList<T> values)
        {
            if ((values == null) || (values.Count == 0))
            {
                this.Write(0);
                return false;
            }
            this.Write(values.Count);
            return true;
        }

        public IList<ByteArraySegment> WriteReturnSegment(byte[] value, int start, int length)
        {
            this._field_n.Clear();
            int index = 0;
            this._field_l.e(value, start, length);
            this._field_k = 0;
            if (this._field_f)
            {
                this._field_c.a(this._field_l);
                this._field_m[index].SetInfo(this._field_c._field_e, this._field_c._field_h - this._field_l._field_d, this._field_l._field_d);
                this._field_n.Add(this._field_m[index]);
                this._field_k += this._field_l._field_d;
                index++;
                while (this._field_k < length)
                {
                    this.a();
                    this._field_c.a(this._field_l);
                    this._field_m[index].SetInfo(this._field_c._field_e, this._field_c._field_h - this._field_l._field_d, this._field_l._field_d);
                    this._field_n.Add(this._field_m[index]);
                    this._field_k += this._field_l._field_d;
                    index++;
                }
            }
            else
            {
                this._field_k = length;
                byte[] dst = new byte[length];
                Buffer.BlockCopy(value, start, dst, 0, length);
                Class_b item = new Class_b(dst);
                this._field_b.Enqueue(item);
                this._field_m[index].SetInfo(dst, 0, dst.Length);
                this._field_n.Add(this._field_m[index]);
            }
            this._field_e += this._field_k;
            return this._field_n;
        }

        public void WriteShortString(string value)
        {
            b().b(value, this.Coding, this._field_c, this, true);
        }

        public void WriteString(string value)
        {
            b().a(value, this.Coding, this._field_c, this, false);
        }

        public unsafe void WriteVariant(double value)
        {
            this.WriteVariant(*((long*) &value));
        }

        public void WriteVariant(int value)
        {
            uint num = (uint) ((value << 1) ^ (value >> 0x1f));
            this.a(num);
        }

        public void WriteVariant(long value)
        {
            ulong num = (ulong) ((value << 1) ^ (value >> 0x3f));
            this.a(num);
        }

        public unsafe void WriteVariant(float value)
        {
            this.WriteVariant(*((int*) &value));
        }

        public void WriteVariant(uint value)
        {
            this.a(value);
        }

        public void WriteVariant(ulong value)
        {
            this.a(value);
        }

        public int Count
        {
            get
            {
                return this._field_e;
            }
        }
    }
}

